<script setup lang="ts">
import {computed, nextTick, ref, useSlots, watch} from 'vue';
import ComponentManager from '../ComponentManager';
import {FormItemConfig} from '../types';
import {deepClone} from "../utils/clone";

const props = defineProps({
  /**
   * 表单数据
   */
  modelValue: {
    type: Object,
    required: true
  },
  /**
   * 表单项配置列表
   * 接收单层数组（一组表单项）
   */
  items: {
    type: Array as () => FormItemConfig[],
    required: true
  }
});

const formData = ref<Record<string, any>>({});
const emit = defineEmits(['update:modelValue']);
const slots = useSlots();

/**
 * 监听表单数据变化
 */
watch(() => props.modelValue, (value) => {
  // 创建一个新对象来强制刷新响应式
  formData.value = deepClone(value);
}, {immediate: true, deep: true});

/**
 * 更新表单数据
 * @param prop 属性名
 * @param value 新值
 */
function updateFormData(prop: string, value: any) {
  // 先使用新对象更新本地数据
  formData.value = {
    ...formData.value,
    [prop]: value
  };

  // 然后向父组件发出更新事件
  nextTick(() => {
    emit('update:modelValue', {...formData.value});
  });
}

/**
 * 计算可显示的表单项
 */
const visibleItems = computed(() => {
  if (!props.items) return [];

  return props.items.map(item => {
    // 处理是否显示
    if (item.showRender && typeof item.showRender === 'function') {
      item.show = item.showRender(formData.value, item);
    }

    return item;
  }).filter(item => item.show !== false);
});

/**
 * 获取组件属性
 */
function getComponentProps(item: FormItemConfig) {
  const componentRegister = ComponentManager.getComponent(item.type || 'custom');

  // 合并默认属性和自定义属性
  return {
    ...deepClone(componentRegister?.defaultProps),
    ...deepClone(item.componentProps),
    modelValue: formData.value[item.prop],
    'onUpdate:modelValue': (value: any) => {
      updateFormData(item.prop, value);
    }
  };
}

/**
 * 检查插槽是否存在
 */
function hasSlot(name: string): boolean {
  return slots && !!slots[name];
}
</script>

<template>
  <div class="fa-form-item-list">
    <template v-for="(item, index) in visibleItems" :key="item.prop">
      <!-- 顶部插槽 -->
      <template v-if="hasSlot(`${item.prop}Top`)">
        <slot :name="`${item.prop}Top`" :item="item"></slot>
      </template>

      <div class="fa-form-item" :class="item.classList">
        <div class="fa-form-item-container">
          <!-- 自定义标签插槽 -->
          <template v-if="item.customLabel && hasSlot(`${item.prop}Label`)">
            <div class="fa-form-label">
              <slot :name="`${item.prop}Label`" :item="item"></slot>
            </div>
          </template>

          <!-- 表单项容器 -->
          <div class="fa-form-field" v-bind="item.itemProps || {}">
            <label v-if="item.label && !item.customLabel" class="fa-form-label-text">
              <span v-if="item.required" class="fa-form-required">*</span>
              {{ item.label }}
            </label>

            <!-- 普通组件渲染 -->
            <div v-if="ComponentManager.has(item.type || 'custom')" class="fa-form-field-component">
              <component
                :is="ComponentManager.getComponent(item.type || 'custom')?.component"
                v-bind="getComponentProps(item)">
              </component>
            </div>

            <!-- 自定义插槽 -->
            <template v-else-if="hasSlot(item.prop)">
              <div>
                <slot :name="item.prop" :item="item"></slot>
              </div>
            </template>
            <!-- 没有匹配的组件和插槽时不显示任何内容 -->
          </div>
        </div>
      </div>

      <!-- 底部插槽 -->
      <template v-if="hasSlot(`${item.prop}Bottom`)">
        <slot :name="`${item.prop}Bottom`" :item="item"></slot>
      </template>
    </template>
  </div>
</template>

<style lang="scss">
.fa-form-item-list {
  .fa-form-item {
    margin-bottom: 12px;

    &:last-child {
      margin-bottom: 0;
    }

    .fa-form-item-container {
      display: flex;
      flex-direction: column;

      .fa-form-field {
        display: flex;
        flex-direction: column;

        .fa-form-label-text {
          font-size: 14px;
          font-weight: 500;
          margin-bottom: 4px;

          .fa-form-required {
            color: #f5222d;
            margin-right: 4px;
          }
        }

        &.horizontal {
          flex-direction: row;
          align-items: center;

          .fa-form-label-text {
            margin-right: 8px;
            margin-bottom: 0;
          }

          .fa-form-field-component {
            flex: 1;
          }
        }
      }
    }
  }
}
</style>
